﻿#include "ICom.h"

#include <QEventLoop>
#include <QTimer>

ICom::ICom(QObject *parent)
    : QObject(parent)
{

}

ICom::~ICom()
{
}

uint16_t ICom::checksum(const QByteArray &data)
{
    uint16_t sum = 0;
    for (uint16_t i = 0; i < data.length(); i++) {
        sum += static_cast<uint8_t>(data[i]);
    }
    return sum;
}

QString ICom::ERR_NOT_OPEN()
{
    return tr("Com device not opened.");
}

void ICom::write(const Tlv &tlv)
{
    if (isOpen()) {
        IWrite(generate(tlv));
        tlv.setRequestMode(true);
        emit dataSend(tlv);
    } else {
        emit errorOccurred(ERR_NOT_OPEN());
    }
}

void ICom::write(const TlvTag &tag, const QByteArray &value)
{
    write(Tlv(tag, value));
}

void ICom::onReadyRead(const QByteArray& data)
{
    m_buffer.append(data);

    // 不断查找帧头和帧尾
    while (true) {
        int headIndex = m_buffer.indexOf(QByteArray("\x5A\xA5", 2));
        if (headIndex < 0)
            break; // 没有帧头

        int tailIndex = m_buffer.indexOf(QByteArray("\xA5\x5A", 2), headIndex + 2);
        if (tailIndex < 0)
            break; // 没有完整帧尾

        int frameLen = tailIndex + 2 - headIndex; // 包含帧尾的长度
        QByteArray frame = m_buffer.mid(headIndex, frameLen);

        parse(frame);

        // 删除已处理的数据
        m_buffer.remove(0, headIndex + frameLen);
    }

    // 防止缓冲无限增长
    if (m_buffer.size() > 4096)
        m_buffer.remove(0, m_buffer.size() - 1024);
}

void ICom::parse(const QByteArray & frame)
{
    // 1层_len
    uint16_t p1Len = getUi16FromBytesBE(frame, 2);
    // 1层数据
    QByteArray p1 = frame.mid(4, p1Len);

    // 1层 tlv0 长度
    uint16_t tlv0Len = 2 + 2 + getUi16FromBytesBE(p1, 2);

    // 1层 tlv1 长度
    uint16_t tlv1Len = 2 + 2 + getUi16FromBytesBE(p1, tlv0Len + 2);

    // 1层 tlv2 长度
    uint16_t tlv2Len = 2 + 2 + getUi16FromBytesBE(p1, tlv0Len + tlv1Len + 2);

    // 2层数据
    QByteArray p2 = p1.mid(tlv0Len + tlv1Len + tlv2Len);

    // Tlv个数
    uint8_t tlvCnt = getByteFromBytes(p2, 0);

    // 获取所有Tlv并发射
    uint16_t idx = 1;
    for (uint8_t i = 0; i < tlvCnt; i++) {
        TlvTag tag = static_cast<TlvTag>(getUi16FromBytesBE(p2, idx));
        uint16_t len = getUi16FromBytesBE(p2, idx + 2);
        QByteArray val = p2.mid(idx + 4, len);
        idx += 4 + len;
        Tlv tlv(tag, val);
        emit dataReceived(tlv);
    }
    emit frameDone();  // 一帧数据结束
}

QByteArray ICom::generate(const Tlv & tlv)
{
    static uint32_t id = 0x00000000;
    // id按大端序转换成QByteArray
    Tlv tlv0(TlvTag::Tlv_seq_id, ui32ToBytesBE(id++));
    Tlv tlv1(TlvTag::Tlv_NULL, QByteArray());
    Tlv tlv2(TlvTag::Tlv_NULL, QByteArray());
    // Tlv tlv0(TlvTag::Tlv_seq_id, QByteArray());
    // Tlv tlv1(TlvTag::Tlv_status, QByteArray());
    // Tlv tlv2(TlvTag::Tlv_reserve, QByteArray());

    QByteArray b0 = tlv0.toBytes();
    QByteArray b1 = tlv1.toBytes();
    QByteArray b2 = tlv2.toBytes();

    // 2层
    QByteArray p2;
    p2.append(0x01);   // tlv个数为1
    p2.append(tlv.toBytes());

    // 1层
    QByteArray p1 = b0 + b1 + b2 + p2;
    uint16_t p1Len = p1.length();

    // 完整数据帧
    QByteArray frame;
    // 帧头
    frame.append('\x5A');
    frame.append('\xA5');

    // 1层长度
    frame.append(getHByte(p1Len));
    frame.append(getLByte(p1Len));

    // 1层数据
    frame.append(p1);

    // 检验和
    uint16_t cs = checksum(p1);
    frame.append(getHByte(cs));
    frame.append(getLByte(cs));

    // 帧尾
    frame.append('\xA5');
    frame.append('\x5A');

    return frame;
}
